/*
 * main.cpp - Grupo 5 - Prog. Avanzada 2011
 *
 *  Javier Dominguez - 4.901.161-6
 *  Marcelo Parada - 1.977.094-9
 *  Rodrigo Ruiz - 4.481.611-2
 *  Maximiliano Silvera - 4.106.938-6
 */
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include "dt/UsuarioDT.h"
#include "logica/IRegistroUsuario.h"
#include "util/ControllerFactory.h"
#include "dt/SingleDT.h"
#include "dt/SolistaDT.h"
#include "dt/BandaDT.h"
#include <exception>
#include "dt/ArtistaDT.h"
#include "dt/AlbumDT.h"

static const int CU_REGISTRO_USUARIO = 1;
static const int CU_COMPARTIR_TEMA_SINGLE = 2;
static const int CU_COMPARTIR_PISTA_ALBUM = 3;
static const int CU_CONSULTAR_INFO_TEMA = 4;
static const int CU_ELIMINAR_TEMA = 5;
static const int CU_ETIQUETAR = 6;
static const int CU_REPRODUCIR_TEMA = 7;
static const int CU_MOSTRAR_LISTADO_USUARIOS = 8;
static const int CONTINUAR = 0;
static const int SALIR = -1;

void cabecera();
void menuPrincipal();
int iniciarCU(int opcion);
int salir();

// CU Solicitados
int registroUsuario();
int compartirTemaSingle();
int compartirPistaAlbum();
int consultarInfoTema();
int eliminarTema();
int etiquetar();
int reproducirTema();
int salir();

using namespace std;

int main()
{
	int opcion;

	while(true)
	{
		menuPrincipal();

		cin >> opcion;

		/*
		 * Se invoca el metodo que corresponda a la opcion seleccionada,
		 * si este retorna 0 entonces se cierra la aplicacion.
		 */
		if(iniciarCU(opcion) == SALIR)
		{
			return SALIR;
		}
	}
}

/*
 * Imprie la cabecera de la pantalla
 */
void cabecera()
{
	system("clear");

	cout << "------------------------------------------------------------------------- \n";
	cout << "|         .:: Prog. Avanzada 2011 - Grupo 5 - Tarea 7 ::.               | \n";
	cout << "------------------------------------------------------------------------- \n\n";
}

/*
 * Dibuja el menu principal
 */
void menuPrincipal()
{
	cabecera();

	cout << "1. Registrar de Usuario." << endl;
	cout << "2. Compartir Tema Single." << endl;
	cout << "3. Compartir Pista Album." << endl;
	cout << "4. Consultar Información Tema." << endl;
	cout << "5. Eliminar Tema." << endl;
	cout << "6. Etiquetar." << endl;
	cout << "7. Reproducir Tema." << endl;
	cout << "0. Salir." << endl << endl;

	cout << "Indique la opcion deseada: ";
}

/*
 * Metodo utilizado por los CU compartir tema single y compartir pista album para obtener los artistas a relacionar
 */
ColConcrete<ArtistaDT*> *solicitarArtistas(string msjSolicitud, ICompartirTemaSingle *cCompTemaSingle, ICompartirPistaAlbum *cCompPistaAlbum)
{
	ColConcrete<ArtistaDT*> *colArtistas = new ColConcrete<ArtistaDT*>();

	cout << endl << msjSolicitud << endl;

	ArtistaDT *artistaDTAux;

	string nombreArtista;

	int integrantesArtista;

	int tipoArtista;

	int opcion;

	do
	{
		cout << "Nombre artista: "; cin >> nombreArtista;

		if(cCompTemaSingle != NULL)
		{
			artistaDTAux = cCompTemaSingle->obtenerArtista(nombreArtista);
		}
		else if(cCompPistaAlbum != NULL)
		{
			artistaDTAux = cCompPistaAlbum->obtenerArtista(nombreArtista);
		}

		// Si no existe el artista
		if(artistaDTAux == NULL)
		{
			cout << "El artista no existe, debe completar todos los datos." << endl;

			cout << "Indique el tipo de artista. [1: Solista, 2: Banda]."; cin >> tipoArtista;

			if(tipoArtista == 1)
			{
				artistaDTAux = new SolistaDT(nombreArtista);
			}
			else if(tipoArtista == 2)
			{
				cout << "Cantidad integrantes: "; cin >> integrantesArtista;

				artistaDTAux = new BandaDT(nombreArtista, integrantesArtista);
			}
		}

		colArtistas->add(artistaDTAux);

		try
		{
			if(cCompTemaSingle != NULL)
			{
				cCompTemaSingle->crearArtista(artistaDTAux);
			}
			else if(cCompPistaAlbum != NULL)
			{
				cCompPistaAlbum->crearArtista(artistaDTAux);
			}
		}
		catch(string e)
		{
			// Nothing
		}

		cout << "Desea agregar otro artista?. [1: SI || 0: No]:";

		cin >> opcion;
	}
	while(opcion == 1);

	return colArtistas;
}

/*
 * Inicia el Caso de uso correspondiente de acuerdo a la opcion
 * ingresada por el usuario
 */
int iniciarCU(int opcion)
{
	cabecera();

	if(opcion == 0)
	{
		return salir();
	}
	else if(opcion == CU_REGISTRO_USUARIO)
	{
		return registroUsuario();
	}
	else if(opcion == CU_COMPARTIR_TEMA_SINGLE)
	{
		return compartirTemaSingle();
	}
	else if(opcion == CU_COMPARTIR_PISTA_ALBUM)
	{
		return compartirPistaAlbum();
	}
	else if(opcion == CU_CONSULTAR_INFO_TEMA)
	{
		return consultarInfoTema();
	}
	else if(opcion == CU_ELIMINAR_TEMA)
	{
		return eliminarTema();
	}
	else if(opcion == CU_ETIQUETAR)
	{
		return etiquetar();
	}
	else if(opcion == CU_REPRODUCIR_TEMA)
	{
		return reproducirTema();
	}

	return 1;
}

int salir()
{
	cout << "Gracias por todo, presione una tecla para salir.";

	getchar();

	getchar();

	system("clear");

	return SALIR;
}

/*
 * CU - Registro de Usuario
 *
 * El caso de uso comienza cuando el Usuario desea crearse en la red.
 * Para ello debe ingresar su nombre completo, mail y el nick que lo identificara en la red.
 * Si el nick ingresado esta disponible, el Sistema registra el nuevo usuario en la red,
 * de lo contrario el Usuario cambia el nick hasta que esta disponible o decida cancelar el registro.
 */
int registroUsuario()
{
	IRegistroUsuario *controller = ControllerFactory::getInstance()->getRegistroUsuarioController();

	/*
	 * Solicito los datos del usuario
	 */
	string nick;

	string nombre;

	string mail;

	cout << "Ingrese los datos del usuario." << endl;

	cout << "Nombre: "; cin >> nombre;

	cout << "E-mail: "; cin >> mail;

	/*
	 * Chequeo si nick esta disponible
	 */
	bool nickDisponible = false;

	int opcion;

	while(!nickDisponible)
	{
		cout << "Nick: ";

		cin >> nick;

		nickDisponible = controller->nickDisponible(nick);

		// Si nick no disponible solicito nuevamente el nick o permito cancelar y vuelve al menu
		if(!nickDisponible)
		{
			cout << "Nick no disponible. [1: Reintentar || 0: Salir]:";

			cin >> opcion;

			if(opcion != 1)
			{
				return SALIR;
			}
		}
	}

	/*
	 * Ingreso la informacion al sistema
	 */
	UsuarioDT *usuarioDT = new UsuarioDT(nick, nombre, mail);

	controller->crearUsuario(usuarioDT);

	cout << endl << "Usuario registrado correctamente.\n";

	getchar();

	getchar();

	// Limpio la memoria
	delete usuarioDT;

	return CONTINUAR;
}

/*
 * CU - Compartir Tema Single
 *
 * El caso de uso comienza cuando el Usuario desea compartir un nuevo single,
 * ingresando el titulo, duracion y año del mismo. Luego ingresa uno a uno los
 * artistas que interpretan el single (al menos uno). En caso de existir el artista
 * en la red ingresa su nombre, mientras que si es nuevo indica su nombre, si es
 * solista o banda y la cantidad de integrantes (si es banda). Para finalizar, el
 * Sistema da de alta el nuevo tema single asi como los nuevos artistas y devuelve un
 * id generado para identificar al tema en el Sistema.
 */
int compartirTemaSingle()
{
	int ret = CONTINUAR;

	ICompartirTemaSingle *controller = ControllerFactory::getInstance()->getCompartirTemaSingleController();

	/*
	 * Solicito informacion de single
	 */
	string tituloSingle;

	int minutosSingle;

	int segundosSingle;

	int anioSingle;

	cout << "Ingrese los datos del Single." << endl;

	cout << "Titulo: "; cin >> tituloSingle;

	cout << "Minutos (dur.): "; cin >> minutosSingle;

	cout << "Segundos (dur.): "; cin >> segundosSingle;

	cout << "Año: "; cin >> anioSingle;

	SingleDT *singleDT = new SingleDT(anioSingle, tituloSingle, new Tiempo(minutosSingle, segundosSingle));

	/*
	 * Solicito los artistas del single
	 */
	ColConcrete<ArtistaDT*> *colArtistasSingle = solicitarArtistas("Ingrese los artistas del single.", controller, NULL);

	/*
	 * Ingreso la informacion al sitema
	 */
	try
	{
		singleDT->setId(controller->crearSingle(singleDT));

		ConcreteIterator<ArtistaDT*> *iterArtistasSingle = colArtistasSingle->getIterator();

		ArtistaDT *currArtistaDT;

		while(iterArtistasSingle->hasCurrent())
		{
			currArtistaDT = iterArtistasSingle->current();

			try
			{
				controller->asociarArtistaTema(currArtistaDT, singleDT);
			}
			catch(string e2)
			{
				cout << "INFO:" << e2 << endl;
			}


			iterArtistasSingle->next();
		}

		cout << "\nSingle compartido correctamente.(Id: " << singleDT->getId() << ").\n";
	}
	catch(string e1)
	{
		cout << "ERROR:" << e1 << endl;

		ret = SALIR;
	}

	getchar();

	getchar();

	/*
	 * Limpio la memoria
	 */
	delete singleDT;

	delete colArtistasSingle; // Este elimina el contenido del iterArtistas y de artistaDT

	return ret;
}

/*
 * CU - Compartir Pista Album
 *
 * El caso de uso comienza cuando el Usuario desea compartir una nueva pista de album,
 * ingresando el titulo, duracion y numero de pista. Luego ingresa uno a uno los artistas
 * que interpretan la pista (al menos uno). En caso de existir el artista en la red
 * ingresa su nombre, mientras que si es nuevo indica su nombre, si es solista o banda
 * y la cantidad de integrantes (si es banda). Una vez ingresados los artistas, el Sistema
 * lista los albumes registrados en la red. El Usuario selecciona uno de ellos o en caso de
 * no estar en el listado lo da de alta ingresando su nombre, anio de edicion y artistas que
 * lo interpretan (de igual forma que para artistas de la pista). Para finalizar, el Sistema
 * de alta la nueva pista de album, los nuevos artistas, el album (si aplica) y devuelve un id
 * generado para identificar al tema en el Sistema.
 */
int compartirPistaAlbum()
{
	int ret = CONTINUAR;

	ICompartirPistaAlbum *controller = ControllerFactory::getInstance()->getCompartirPistaAlbumController();

	/*
	 * Solicito informacion de pista
	 */
	string tituloPista;

	int numeroPista;

	int minutosPista;

	int segundosPista;

	cout << "Ingrese los datos de la Pista. \n";

	cout << "Titulo: "; cin >> tituloPista;

	cout << "Minutos (dur.): "; cin >> minutosPista;

	cout << "Segundos (dur.): "; cin >> segundosPista;

	cout << "Numero de Pista: "; cin >> numeroPista;

	PistaDT *pistaDT = new PistaDT(numeroPista, tituloPista, new Tiempo(minutosPista, segundosPista));

	/*
	 * Solicito los artistas de la pista
	 */
	ColConcrete<ArtistaDT*> *colArtistasPista = solicitarArtistas("Ingrese los artisas de la pista.", NULL, controller);

	/*
	 * Solicitar album de la pista
	 */
	AlbumDT *albumDT = NULL;

	int opcion;

	string nombreAlbum;

	int anioEdicionAlbum;

	cout << "Albumes registrados." << endl << controller->obtenerListadoAlbumes()->toString();

	cout << endl << "Seleccionar album. [1: De la lista || 0: Ingrese nuevo album]: "; cin >> opcion;

	cout << "Ingrese nombre del Album: "; cin >> nombreAlbum;

	if(opcion == 0)
	{
		cout << "Ingrese año de edicion: "; cin >> anioEdicionAlbum;

		albumDT = new AlbumDT(nombreAlbum, anioEdicionAlbum);
	}

	while(albumDT == NULL)
	{
		albumDT = controller->obtenerAlbum(nombreAlbum);

		if(albumDT == NULL)
		{
			cout << "El album no existe. [1: Reintentar || 0: Salir]:"; cin >> opcion;

			if(opcion != 1)
			{
				return SALIR;
			}

			cout << "Ingrese nombre album: "; cin >> nombreAlbum;
		}
	}

	/*
	 * Solicito los artistas del album
	 */
	ColConcrete<ArtistaDT*> *colArtistasAlbum = solicitarArtistas("Ingrese los artistas del album.", NULL, controller);

	/*
	 * Ingreso la informacion a el sistema
	 */
	try
	{
		try
		{
			pistaDT->setId(controller->crearPista(pistaDT));
		}
		catch(string e2)
		{
			cout <<  "INFO:" << e2 << endl;
		}

		try
		{
			controller->crearAlbum(albumDT);
		}
		catch(string e2)
		{
			cout <<  "INFO:" << e2 << endl;
		}

		controller->asociarAlbumPista(albumDT, pistaDT); // Asocio el album a la pista

		ArtistaDT *currArtistaDT;

		// Asocio los artistas a la pista
		ConcreteIterator<ArtistaDT*> *iterArtistasPista = colArtistasPista->getIterator();

		while(iterArtistasPista->hasCurrent())
		{
			currArtistaDT = iterArtistasPista->current();

			try
			{
				controller->asociarArtistaTema(currArtistaDT, pistaDT);
			}
			catch(string e2)
			{
				cout << "INFO:" << e2 << endl;
			}

			iterArtistasPista->next();
		}

		// Asocio los artistas al album
		ConcreteIterator<ArtistaDT*> *iterArtistasAlbum = colArtistasAlbum->getIterator();

		while(iterArtistasAlbum->hasCurrent())
		{
			currArtistaDT = iterArtistasAlbum->current();

			try
			{
				controller->asociarArtistaAlbum(currArtistaDT, albumDT);
			}
			catch(string e2)
			{
				cout << "INFO:" << e2 << endl;
			}

			iterArtistasAlbum->next();
		}

		cout << "\nPista compartida correctamente. (Id: " << pistaDT->getId() << ").\n";
	}
	catch(string e1)
	{
		cout << "ERROR:" << e1 << endl;

		ret = SALIR;
	}

	getchar();

	getchar();

	// Limpio la memoria

	delete pistaDT;

	delete albumDT;

	delete colArtistasPista;

	delete colArtistasAlbum;


	return CONTINUAR;
}

/*
 * CU - Consultar Informacion de Tema
 *
 * El caso de uso comienza cuando el Usuario quiere obtener la informacion de un tema. Para ello
 * ingresa el id de un tema a consultar y el Sistema muestra toda la informacion del tema
 * incluyendo los datos de sus artistas, album (si aplica), cantidad de reproducciones totales
 * y fecha de ultima reproduccion
 */
int consultarInfoTema()
{
	IConsultarInformacionTema *controller = ControllerFactory::getInstance()->getConsultarInformacionTemaController();
	/*
	 * Solicito el tema a escuchar
	 */
	int idTema;

	cout << "Ingrese el Id del Tema:"; cin >> idTema;

	TemaDT *temaDT = controller->obtenerInfoTema(idTema);

	ReproduccionDT *repDT = controller->obtenerReproduccionTema(idTema);

	// Imprimo la info basica del tema
	cout << "Informacion basica del tema." << endl;

	cout << temaDT->toString() << endl << endl;

	cout << "Artistas del tema." << endl;


	return CONTINUAR;
}

/*
 * CU - Eliminar Tema
 *
 * El caso de uso comienza cuando el Usuario desea quitar un tema de la red. Para ello el
 * Sistema muestra una lista de temas compartidos en la red. El Usuario selecciona de esa
 * lista el id del tema a eliminar y el Sistema lo elimina s�lo en caso de que no haya sido
 * escuchado por ning�n usuario de la red, de lo contrario se genera un error y no se elimina el tema.
 */
int eliminarTema()
{


	return 1;
}

/*
 * CU - Etiquetar
 *
 * El caso de uso comienza cuando el Usuario desea etiquetar un �lbum o artista registrado.
 * Para ello indica el elemento a etiquetar (�lbum o artista) y el Sistema muestra la
 * informaci�n completa de los elementos disponibles en la red de acuerdo a la opci�n
 * ingresada. Luego el Usuario selecciona el elemento a etiquetar de la lista correspondiente
 * y el Sistema muestra sus etiquetas y lista adem�s las disponibles en la red. El Usuario
 * agrega una a una las etiquetas (al menos una) y en caso de querer utilizar etiquetas no
 * registradas, ingresa el nombre de cada nueva etiqueta. Para finalizar, el Sistema muestra
 * la informaci�n del elemento a etiquetar y sus nuevas etiquetas, debiendo el Usuario confirmar
 * o cancelar dicho etiquetado. En caso de confirmar, el Sistema efect�a el etiquetado y da de
 * alta las nuevas etiquetas.
 */
int etiquetar()
{
	return 1;
}

/*
 * CU - Reproducir Tema
 *
 * El caso de uso comienza cuando el Usuario desea escuchar un tema. Para ello puede hacerlo
 * indicando directamente su nick y el id del tema a escuchar o bien buscando por etiquetas.
 * En este �ltimo caso el Sistema muestra un listado de etiquetas registradas, de las cuales
 * el Usuario selecciona una. A partir de esta selecci�n el Sistema muestra los temas de los
 * artistas o �lbumes que contengan esa etiqueta. Para finalizar el Usuario ingresa el id de
 * un tema del listado (y su nick) y el Sistema registra la reproducci�n del tema.
 */
int reproducirTema()
{
	return 1;
}
